package boot.spring.aspect;

import boot.spring.annotation.CanalRedis;
import boot.spring.utils.RedisUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Aspect
@Order(-1)  // 该切面应当先于 @Transactional 执行
@Component
public class CanalRedisAspect {

    @Autowired
    RedisUtil redisUtil;
    SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
    EvaluationContext context = new StandardEvaluationContext();

    @Around("@annotation(boot.spring.annotation.CanalRedis)")
    public Object Around(ProceedingJoinPoint point) throws Throwable {
        // 获取 该函数该注解上面的 参数
        Method method = ((MethodSignature) point.getSignature()).getMethod();
        CanalRedis annotation = method.getAnnotation(CanalRedis.class);
        String table = annotation.table();
        String[] refTables = annotation.refTables();
        String key = annotation.key();
        int expires = annotation.expires();
        // 获取 key的 表达式
        String sString;
        if (!"".equals(key)){
            final Expression expression = spelExpressionParser.parseExpression(key);
            // 获取 该函数上面的 参数
            Object[] args = point.getArgs();
            for (int i = 0; i < args.length; i++) context.setVariable("p"+i, args[i]);
            Object s = expression.getValue(context);
            sString = s==null?"":(s.toString());
        }else{
            sString = "";
        }
        Object res = redisUtil.getValueByChangeTable(table,sString,refTables);
        if (res==null){
            Object o = point.proceed(); //调用目标方法
            // 存储缓存，并且记录时间
            redisUtil.setValueByChangeTable(table,sString,o,refTables,expires);
            return o;
        }else{
            return res;
        }
    }

}